﻿using DA6502.CPU;
using System;
using System.Windows.Forms;

namespace DA6502
{
    using addr = System.UInt16;



    public partial class RegisterPanel : UserControl
    {
        private addr _pc;
        private byte _a;
        private byte _x;
        private byte _y;
        private byte _s;
        private byte _p;


        public delegate void OnRegisterChangeHandler(REGISTER_BYTE reg, byte val);
        public delegate void OnPcChangedHandler(ushort val);
        public event OnRegisterChangeHandler OnRegisterChange;
        public event OnPcChangedHandler OnPcChange;

        public bool CallbackEnable = true;

        /// <summary>
        /// 程序计数器PC
        /// </summary>
        public addr PC
        {
            get => _pc;
            set
            {
                _pc = value;
                txtPC.Text = value.ToString("X4");
                if (OnPcChange != null && CallbackEnable) OnPcChange(value);
            }
        }

        /// <summary>
        /// 累加器A
        /// </summary>
        public byte A
        {
            get => _a;
            set
            {
                _a = value;
                txtA.Text = value.ToString("X2");
                if (OnRegisterChange != null && CallbackEnable) OnRegisterChange(REGISTER_BYTE.A, value);
            }
        }

        /// <summary>
        /// 变址寄存器X
        /// </summary>
        public byte X
        {
            get => _x;
            set
            {
                _x = value;
                txtX.Text = value.ToString("X2");
                if (OnRegisterChange != null && CallbackEnable) OnRegisterChange(REGISTER_BYTE.X, value);
            }
        }

        /// <summary>
        /// 累加器Y
        /// </summary>
        public byte Y
        {
            get => _y;
            set
            {
                _y = value;
                txtY.Text = value.ToString("X2");
                if (OnRegisterChange != null && CallbackEnable) OnRegisterChange(REGISTER_BYTE.Y, value);
            }

        }

        /// <summary>
        /// 堆栈指针S（也称SP）
        /// </summary>
        public byte S
        {
            get => _s;
            set
            {
                _s = value;
                txtS.Text = value.ToString("X2");
                if (OnRegisterChange != null && CallbackEnable) OnRegisterChange(REGISTER_BYTE.S, value);
            }
        }

        /// <summary>
        /// 状态寄存器P
        /// </summary>
        public byte P
        {
            get => _p;
            set
            {
                _p = value;
                txtP.Text = value.ToString("X2");
                SetFlags();
                if (OnRegisterChange != null && CallbackEnable) OnRegisterChange(REGISTER_BYTE.P, value);
            }
        }


        public bool FlagN
        {
            get => blpN.Checked;

            set
            {
                blpN.Checked = value;
                if (value)
                    P |= 0b10000000;
                else
                    P &= 0b01111111;
            }
        }

        public bool FlagV
        {
            get => blpV.Checked;
            set
            {
                blpV.Checked = value;
                if (value)
                    P |= 0b01000000;
                else
                    P &= 0b10111111;
            }
        }

        public bool FlagU
        {
            get => blpU.Checked;
            set
            {
                blpU.Checked = value;
                if (value)
                    P |= 0b00100000;
                else
                    P &= 0b11011111;
            }
        }

        public bool FlagB
        {
            get => blpB.Checked;
            set
            {
                blpB.Checked = value;
                if (value)
                    P |= 0b00010000;
                else
                    P &= 0b11101111;
            }
        }

        public bool FlagD
        {
            get => blpD.Checked;
            set
            {
                blpD.Checked = value;
                if (value)
                    P |= 0b00001000;
                else
                    P &= 0b11110111;
            }
        }

        public bool FlagI
        {
            get => blpI.Checked;
            set
            {
                blpI.Checked = value;
                if (value)
                    P |= 0b00000100;
                else
                    P &= 0b11111011;
            }
        }
        public bool FlagZ
        {
            get => blpZ.Checked;
            set
            {
                blpZ.Checked = value;
                if (value)
                    P |= 0b00000010;
                else
                    P &= 0b11111101;
            }
        }
        public bool FlagC
        {
            get => blpC.Checked;
            set
            {
                blpC.Checked = value;
                if (value)
                    P |= 0b00000001;
                else
                    P &= 0b11111110;
            }
        }

        public RegisterPanel()
        {
            InitializeComponent();
            PC = 0x0000;
            A = 0x00;
            X = 0x00;
            Y = 0x00;
            S = 0x00;
            P = 0x00;
        }

        public RegisterPanel(DA6502.CPU.Registers r)
        {
            PC = r.PC;
            A = r.A;
            X = r.X;
            Y = r.Y;
            S = r.S;
            P = r.P;
        }

        private bool CheckInputKey(KeyPressEventArgs e)
        {
            return !((e.KeyChar >= '0' && e.KeyChar <= '9')
                || (e.KeyChar >= 'A' && e.KeyChar <= 'F')
                || (e.KeyChar >= 'a' && e.KeyChar <= 'f')
                || (e.KeyChar == 'X' || e.KeyChar == 'x'));
        }
        private void SetFlags()
        {
            blpN.Checked = (_p & 0x80) > 0;
            blpV.Checked = (_p & 0x40) > 0;
            blpU.Checked = (_p & 0x20) > 0;
            blpB.Checked = (_p & 0x10) > 0;
            blpD.Checked = (_p & 0x08) > 0;
            blpI.Checked = (_p & 0x04) > 0;
            blpZ.Checked = (_p & 0x02) > 0;
            blpC.Checked = (_p & 0x01) > 0;
        }

        private void ToggleFlag(object sender, EventArgs e)
        {
            BitLamp blp = (BitLamp)sender;
            if (blp.Checked)
                P |= (byte)blp.Tag;
            else
                P &= (byte)~(byte)blp.Tag;
        }

        private void Txt_keyPress(object sender, KeyPressEventArgs e)
        {
            e.Handled = CheckInputKey(e);
        }

        private void Txt_Leave(object sender, EventArgs e)
        {
            TextBox tbox = (TextBox)sender;
            string t = tbox.Text;
            byte v = 0x00;
            try
            {
                if (t.Substring(0, 2).ToLower() != "0x") t = "0x" + t;
                v = Convert.ToByte(t, 16);
            }
            catch (ArgumentException)
            { }
            catch (FormatException)
            {
                MessageBox.Show(tbox.Tag + "的值应为16进制数字");
            }
            catch (OverflowException)
            {
                MessageBox.Show(tbox.Tag + "的值应不大于0xFF");
            }

            switch (tbox.Tag)
            {
                case "A": _a = v; break;
                case "X": _x = v; break;
                case "Y": _y = v; break;
                case "S": _s = v; break;
                case "P": _p = v; break;
            }
            tbox.Text = v.ToString("X2");
            if ((string)tbox.Tag == "P") SetFlags();
        }

        private void TxtPC_Leave(object sender, EventArgs e)
        {
            string t = txtPC.Text;
            addr v = 0x0000;
            try
            {
                if (t.Length > 2 && t.Substring(0, 2).ToLower() != "0x") t = "0x" + t;
                v = Convert.ToUInt16(t, 16);
            }
            catch (ArgumentException)
            { }
            catch (FormatException)
            {
                MessageBox.Show("P的值应为16进制数字");
            }
            catch (OverflowException)
            {
                MessageBox.Show("P的值应不大于0xFFFF");
            }

            _pc = v;
            txtPC.Text = v.ToString("X4");
        }

        private void TxtPC_TextChanged(object sender, EventArgs e)
        {

        }
    }
}